﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Windows.JControls.JColorPicker.Utils;

namespace System.Windows.JControls
{
    public partial class JSColorPickerControl : UserControl
    {
        /// <summary>
        /// Occurs, when the selected color is changed.
        /// </summary>
        public event EventHandler SelectedColorChanged;

        private HSB selectedHSB;
        private RGB selectedRGB;

        private bool _valueChanging = false;

        /// <summary>
        /// Initialze an object
        /// </summary>
        public JSColorPickerControl()
        {
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);
            InitializeComponent();

            // init
            SelectedColor = Color.Red;
        }

        #region Properties

        /// <summary>
        /// Get or set the selected color as HSB.
        /// </summary>
        public HSB HSB
        {
            get { return selectedHSB; }
            set
            {
                selectedHSB = value;
                SetHSBTracker(value);
                SetAlphaTracker(255);
            }
        }

        /// <summary>
        /// Get or set the selected as RGB.
        /// </summary>
        public RGB RGB
        {
            get { return selectedRGB; }
            set
            {
                selectedRGB = value;
                SetRGBTracker(value);
                SetAlphaTracker(255);
            }
        }

        /// <summary>
        /// Get or set the selected color.
        /// </summary>
        public Color SelectedColor
        {
            get { return Color.FromArgb((int)alphaTracker1.Value, selectedRGB.Red, selectedRGB.Green, selectedRGB.Blue); }
            set
            {
                SetRGBTracker(new RGB(value.R, value.G, value.B));
                SetAlphaTracker(value.A);
            }
        }


        #endregion

        #region Set values

        /// <summary>
        /// Set the values from the RGB-Tracker based on the given RGB object.
        /// </summary>
        /// <param name="rgb"></param>
        private void SetRGBTracker(RGB rgb)
        {
            JColorPickerHelper.ColorTrackerValueChange(rgbTrackerRed, rgb.Red);
            JColorPickerHelper.ColorTrackerValueChange(rgbTrackerGreen, rgb.Green);
            JColorPickerHelper.ColorTrackerValueChange(rgbTrackerBlue, rgb.Blue);
        }

        /// <summary>
        /// Set the values from the NumericUpDown-Controls based on the given RGB object.
        /// </summary>
        /// <param name="rgb"></param>
        private void SetRGBNumericValues(RGB rgb)
        {
            JColorPickerHelper.NumericUpDownValueChanged(nupRGB_Blue, Convert.ToDecimal(rgb.Blue));
            JColorPickerHelper.NumericUpDownValueChanged(nupRGB_Green, Convert.ToDecimal(rgb.Green));
            JColorPickerHelper.NumericUpDownValueChanged(nupRGB_Red, Convert.ToDecimal(rgb.Red));
        }

        /// <summary>
        /// Set the values from the HSB-Tracker based on the given HSB object.
        /// </summary>
        /// <param name="hsb"></param>
        private void SetHSBTracker(HSB hsb)
        {
            JColorPickerHelper.ColorTrackerValueChange(hsbHueTracker1, hsb.Hue);
            JColorPickerHelper.ColorTrackerValueChange(hsbSaturationTracker1, hsb.Saturation * 100);
            JColorPickerHelper.ColorTrackerValueChange(hsbBrightnessTracker1, hsb.Brightness * 100);
        }

        /// <summary>
        /// Set the values from the NumericUpDown-Controls based on the given HSB object.
        /// </summary>
        /// <param name="hsb"></param>
        private void SetHSBNumericValues(HSB hsb)
        {
            JColorPickerHelper.NumericUpDownValueChanged(nupHSBHue, (decimal)hsb.Hue);
            JColorPickerHelper.NumericUpDownValueChanged(nupHSBSaturation, (decimal)(hsb.Saturation * 100));
            JColorPickerHelper.NumericUpDownValueChanged(nupHSBBrightness, (decimal)(hsb.Brightness * 100));
        }

        /// <summary>
        /// Sett the values from the NumericUpDown-Controls for alpha
        /// </summary>
        /// <param name="value"></param>
        private void SetAlphaNumericValue(decimal value)
        {
            JColorPickerHelper.NumericUpDownValueChanged(nupAlpha, value);
        }

        private void SetAlphaTracker(double value)
        {
            JColorPickerHelper.ColorTrackerValueChange(alphaTracker1, value);
        }

        private void SetAlphaColor(Color color)
        {
            alphaTracker1.ColorAlpha = color;
        }

        private void SetColorWheelHSB(HSB hsb)
        {
            colorWheel1.SelectedHSBColor = hsb;
        }

        private void SetHSBColor(Color color)
        {
            hsbBrightnessTracker1.ColorTracker = color;
            hsbSaturationTracker1.ColorTracker = color;
        } 

        #endregion

        #region Paint

        /// <summary>
        /// Paint the selected color
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Rectangle rectColor = GetPaintColorRectangle();

            // paint selected color
            using (SolidBrush brush = new SolidBrush(Color.FromArgb((int)alphaTracker1.Value, selectedRGB.ToColor())))
            {
                e.Graphics.FillRectangle(brush, rectColor);
            }

            // paint black border
            using (Pen pen = new Pen(Color.Black, 2))
            {
                e.Graphics.DrawRectangle(pen, rectColor);
            }
        }

        /// <summary>
        /// Returns the area after the label7 for painting the selected color.
        /// </summary>
        /// <returns></returns>
        private Rectangle GetPaintColorRectangle()
        {
            return new Rectangle(label7.Location.X + label7.Width + 5,
                                (label7.Location.Y + (label7.Size.Height / 2)) - (36 / 2),
                                 36,
                                 36);
        } 

        #endregion

        #region Event

        protected virtual void OnSelectedColorChanged(object sender, EventArgs args)
        {
            if (SelectedColorChanged != null)
            {
                SelectedColorChanged(sender, args);
            }
        }

        private void nupRGB_Red_Enter(object sender, EventArgs e)
        {
            NumericUpDown ctr = (NumericUpDown)sender;
            ctr.Select();
        }

        #region Tracker value changed

        private void RGBTrackerValueChanged(object sender, EventArgs e)
        {
            if (_valueChanging == false)
            {
                _valueChanging = true;

                // RGB
                RGB rgb = new RGB((int)rgbTrackerRed.Value, (int)rgbTrackerGreen.Value, (int)rgbTrackerBlue.Value);
                SetRGBNumericValues(rgb);
                SetAlphaColor(rgb.ToColor());
                SetHSBColor(rgb.ToColor());

                // HSB
                HSB hsb = ColorSpaceHelper.RGBtoHSB(rgb);
                SetHSBTracker(hsb);
                SetHSBNumericValues(hsb);
                SetColorWheelHSB(new HSB(hsb.Hue, hsb.Saturation, 1));

                selectedHSB = hsb;
                selectedRGB = rgb;

                Invalidate(GetPaintColorRectangle(), false);

                OnSelectedColorChanged(this, null);
                _valueChanging = false;
            }
        }

        private void HSBTrackerValueChanged(object sender, EventArgs e)
        {
            if (_valueChanging == false)
            {
                _valueChanging = true;

                // HSB
                HSB hsb = new HSB(hsbHueTracker1.Value, hsbSaturationTracker1.Value / 100, hsbBrightnessTracker1.Value / 100);
                SetHSBNumericValues(hsb);
                SetColorWheelHSB(new HSB(hsb.Hue, hsb.Saturation, 1));

                // RGB
                RGB rgb = ColorSpaceHelper.HSBtoRGB(hsb);
                SetRGBTracker(rgb);
                SetRGBNumericValues(rgb);
                SetAlphaColor(rgb.ToColor());
                SetHSBColor(rgb.ToColor());

                selectedHSB = hsb;
                selectedRGB = rgb;

                Invalidate(GetPaintColorRectangle(), false);
                OnSelectedColorChanged(this, null);
                _valueChanging = false;
            }
        }

        private void alphaTracker1_ValueChanged(object sender, EventArgs e)
        {
            if (_valueChanging == false)
            {
                _valueChanging = true;

                SetAlphaNumericValue((decimal)alphaTracker1.Value);
                OnSelectedColorChanged(this, null);
                _valueChanging = false;
            }
        } 

        #endregion

        #region Numeric changed

        private void NumericRGBValueChanged(object sender, EventArgs e)
        {
            if (_valueChanging == false)
            {
                _valueChanging = true;

                // RGB
                RGB rgb = new RGB((int)nupRGB_Red.Value, (int)nupRGB_Green.Value, (int)nupRGB_Blue.Value);
                SetRGBTracker(rgb);
                SetAlphaColor(rgb.ToColor());
                SetHSBColor(rgb.ToColor());

                // HSB
                HSB hsb = ColorSpaceHelper.RGBtoHSB(rgb);
                SetHSBTracker(hsb);
                SetHSBNumericValues(hsb);
                SetColorWheelHSB(new HSB(hsb.Hue, hsb.Saturation, 1));

                selectedHSB = hsb;
                selectedRGB = rgb;

                Invalidate(GetPaintColorRectangle(), false);
                OnSelectedColorChanged(this, null);

                _valueChanging = false;
            }
        }

        private void NumericHSBValueChanged(object sender, EventArgs e)
        {
            if (_valueChanging == false)
            {
                _valueChanging = true;

                // HSB
                HSB hsb = new HSB((double)nupHSBHue.Value, (double)nupHSBSaturation.Value / 100, (double)nupHSBBrightness.Value / 100);
                SetHSBTracker(hsb);
                SetColorWheelHSB(new HSB(hsb.Hue, hsb.Saturation, 1));

                // RGB
                RGB rgb = ColorSpaceHelper.HSBtoRGB(hsb);
                SetRGBTracker(rgb);
                SetRGBNumericValues(rgb);
                SetAlphaColor(rgb.ToColor());
                SetHSBColor(rgb.ToColor());

                selectedHSB = hsb;
                selectedRGB = rgb;
                Invalidate(GetPaintColorRectangle(), false);
                OnSelectedColorChanged(this, null);

                _valueChanging = false;
            }
        }

        private void NumericAlphaValueChanged(object sender, EventArgs e)
        {
            if (_valueChanging == false)
            {
                _valueChanging = true;

                SetAlphaTracker((double)nupAlpha.Value);
                OnSelectedColorChanged(this, null);

                _valueChanging = false;
            }
        } 

        #endregion

        #region Color Wheel changed

        private void colorWheel1_SelectedColorChanged(object sender, EventArgs e)
        {
            if (_valueChanging == false)
            {
                this.SelectedColor = ColorSpaceHelper.HSBtoColor(colorWheel1.SelectedHSBColor);
            }
        } 

        #endregion

        #endregion
    }
}
